home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d21 / dvglue10.arc / UIMBUILD.C < prev    next >
C/C++ Source or Header  |  1988-08-13  |  13KB  |  362 lines

  1. /*======================================================*/
  2. /*  UIMBUILD.C                                          */
  3. /*                                                      */
  4. /* (c) Copyright 1988 Ralf Brown.  All Rights Reserved. */
  5. /*======================================================*/
  6.  
  7. #include <mem.h>
  8. #include <string.h>
  9. #include "tvapi.h"
  10. #include "tvstream.h"
  11. #include "tvui.h"
  12.  
  13. /*======================================================*/
  14. /*======================================================*/
  15.  
  16. #define physical_screen_height() ((*(BYTE far *)0x00400084L)+1)
  17. #define physical_screen_width()  (*(int far *)0x0040004AL)
  18. #define PRIVATE(type) static type near pascal
  19.  
  20. #define HEADER_SIZE 4
  21.  
  22. /*======================================================*/
  23. /*======================================================*/
  24.  
  25. static BYTE fixed_stream_header[] =
  26.    {
  27.    S_WINDOW(0),         /* will fill in length later */
  28.    WS_HIDDEN,           /* hide until we finish our setup */
  29.    WS_LSIZE(0,0),       /* will fill in logical size later */
  30.    WS_WINPOS(0,0),      /* will fill in window position later */
  31.    WS_WINSIZE(0,0),     /* will fill in window size later */
  32.    WS_NOFRAME,          /* we don't want a frame */
  33.    WS_LOGATTR,          /* we want logical attributes */
  34.    WS_WRITEATTR,        /* change attributes when writing */
  35.    WS_NOCTRLCHAR,
  36.    WS_SETCOLOR(1),      /* use normal attribute */
  37.    WS_CLEAR,            /* and clear screen to that color */
  38.    WS_SETCOLOR(3),      /* change to border color */
  39.    WS_CURSPOS(0,1),     /* home cursor */
  40.    WS_MANYCHAR(0,223),  /* write top edge of border, fill in count later */
  41.    WS_SETCURSCOL(0),    /* back to left edge */
  42.    WS_REPEAT(0),        /* will fill in count later */
  43.    WS_CHARS(1),222,     /* write left edge of border */
  44.    WS_SETCURSCOL(0),    /* fill in later, moves to right edge */
  45.    WS_CHARS(1),221,     /* write right edge of border */
  46.    WS_DOREPEAT,
  47.    WS_CURSPOS(0,1),     /* fill in row later */
  48.    WS_MANYCHAR(0,220),  /* write bottom edge of border, fill in count later */
  49.    WS_SETCOLOR(9),      /* reverse video for title */
  50.    WS_SETCURSROW(1),
  51.    WS_SETCURSCOL(0),    /* fill in column later */
  52.    WS_MANYCHARS(0),     /* fill in count later */
  53.    /* rest of stream must be built at runtime */
  54.    } ;
  55.  
  56. static BYTE fixed_stream_trailer[] = {
  57.    WS_FLDCURS(1),
  58.    WS_UPDATE,
  59.    S_MANAGER(9), 0xBD,  /* enable one of DESQview's extensions, don't know which */
  60.    MS_CURRFLDPOS, 0, 0,
  61.    MS_DISALLOW | TV_HMOVE,
  62.    MS_DISALLOW | TV_VMOVE,
  63.    MS_WINTOP, MS_FLDMARKER(0xAF)  /* default field marker is » */
  64.    } ;
  65.  
  66. /*======================================================*/
  67. /*======================================================*/
  68.  
  69. void * pascal UImenu_build(MENU_ITEM *menu_items,MENU_OPTIONS *menu_options)
  70. {
  71.    register int tmp ;
  72.    int stream_size ;
  73.    BYTE *stream_start, *stream ;
  74.    int two_keys = FALSE ;
  75.    int phys_width = physical_screen_width() ;
  76.    int phys_height = physical_screen_height() ;
  77.    int num_fields = 0 ;
  78.    MENU_ITEM *menu_item ;
  79.    int width = 0 ;
  80.    int height = 4 ;  /* top & bottom edges + title + key echo area */
  81.    int overhead ;    /* how much space we need for menu's keystrokes */
  82.    int row, col ;
  83.    int line ;
  84.  
  85. /* find out whether we'll need one space or two for the menu's keystrokes */
  86.  
  87.    for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
  88.       if ((menu_item->type == M_ITEM || menu_item->type == M_SPECIAL) &&
  89.           menu_item->key2 != 0)
  90.          {
  91.          two_keys = TRUE ;
  92.          break ;
  93.          }
  94.    overhead = (two_keys ? 4 : 3) ;
  95.  
  96. /* determine how much memory to allocate for the stream, and simultaneously */
  97. /* how big the menu window will be */
  98.  
  99.    stream_size = sizeof( fixed_stream_header ) +
  100.                  sizeof( fixed_stream_trailer ) +
  101.                  strlen(menu_options->title) + sizeof(FT_HEADER) + 7 ;
  102.    for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
  103.       {
  104.       switch (menu_item->type)
  105.          {
  106.          case M_ITEM:
  107.             if (menu_item->entry == NULL || *menu_item->entry == '\0')
  108.                return ME_BADITEM ;
  109.             tmp = strlen(menu_item->entry) ;
  110.             stream_size += tmp + ((two_keys && menu_item->key2 != 0) ? 11 : 10) ;
  111.             num_fields++ ;
  112.             if (tmp + overhead > width)
  113.                width = tmp + overhead ;
  114.             break ;
  115.          case M_HTEXT:
  116.          case M_TEXT:
  117.             stream_size += 4 ;
  118.             if (menu_item->entry && strlen(menu_item->entry) > 0)
  119.                {
  120.                tmp = strlen(menu_item->entry) ;
  121.                stream_size += tmp + ((menu_item->type == M_HTEXT) ? 6 : 2) ;
  122.                if (tmp > width)
  123.                   width = tmp ;
  124.                }
  125.             break ;
  126.          case M_CENTER:
  127.          case M_HCENTER:
  128.             stream_size += 2 ;
  129.             if (menu_item->entry && strlen(menu_item->entry) > 0)
  130.                {
  131.                tmp = strlen(menu_item->entry) ;
  132.                stream_size += tmp + ((menu_item->type == M_HCENTER) ? 8 : 4) ;
  133.                if (tmp > width)
  134.                   width = tmp ;
  135.                }
  136.             break ;
  137.          case M_SEP:
  138.             stream_size += 7 ;
  139.             break ;
  140.          case M_SPECIAL:
  141.             if (menu_item->entry == NULL || strchr(menu_item->entry,' ') == NULL)
  142.                return ME_BADITEM ;
  143.             tmp = strlen(menu_item->entry) ;
  144.             stream_size += tmp + 10 ;
  145.             num_fields++ ;
  146.             if (tmp > width)
  147.                width = tmp ;
  148.             break ;
  149.          case M_IGNORE:
  150.             /* do nothing */
  151.             break ;
  152.          default:
  153.             return ME_BADITEM ;  /* indicate error */
  154.          }
  155.       if (menu_item->type != M_IGNORE)
  156.          height++ ;
  157.       }
  158.    stream_size += num_fields*sizeof(FT_ENTRY) ;
  159.    if (two_keys)
  160.       stream_size += sizeof(FT_ENTRY) ;
  161.    if (strlen(menu_options->title) > width)
  162.       width = strlen(menu_options->title) ;
  163.    width += 4 ;  /* left & right edge, blanks just inside edges */
  164.  
  165. /* perform some simple error checks before proceeding */
  166.  
  167.    if (height > phys_height || width > phys_width)
  168.       return ME_TOOBIG ;
  169.    if ((stream_start = (BYTE *)malloc(stream_size+HEADER_SIZE)) == NULL)
  170.       return ME_NOMEM ;
  171.  
  172. /* determine upper left corner of menu window */
  173.  
  174.    if (menu_options->row < 0)
  175.       {
  176.       row = phys_height - height + menu_options->row + 1 ;
  177.       if (row < 0)
  178.          row = 0 ;
  179.       }
  180.    else
  181.       {
  182.       row = menu_options->row ;
  183.       if (row + height > phys_height)
  184.          row = phys_height - height ;
  185.       }
  186.    if (menu_options->col < 0)
  187.       {
  188.       col = phys_width - width + menu_options->col + 1 ;
  189.       if (col < 0)
  190.          col = 0 ;
  191.       }
  192.    else
  193.       {
  194.       col = menu_options->col ;
  195.       if (col + width > phys_width)
  196.          col = phys_width - width ;
  197.       }
  198.  
  199. /* start building the stream */
  200.  
  201.    stream = stream_start ;
  202.    *((int *)stream)++ = stream_size ;
  203.    *((int *)stream)++ = num_fields ;
  204.    memcpy( stream, fixed_stream_header, sizeof( fixed_stream_header ) ) ;
  205.    *((int *)(stream+2)) = stream_size - sizeof( fixed_stream_trailer ) ;
  206.    stream[HEADER_SIZE+2] = height ;
  207.    stream[HEADER_SIZE+3] = width ;
  208.    stream[HEADER_SIZE+5] = row ;
  209.    stream[HEADER_SIZE+6] = col ;
  210.    stream[HEADER_SIZE+8] = height ;
  211.    stream[HEADER_SIZE+9] = width ;
  212.    stream[HEADER_SIZE+23] = width-2 ;
  213.    stream[HEADER_SIZE+28] = height ;
  214.    stream[HEADER_SIZE+32] = width-1 ;
  215.    stream[HEADER_SIZE+37] = height-1 ;
  216.    stream[HEADER_SIZE+40] = width-2 ;
  217.    stream += sizeof( fixed_stream_header ) ;
  218.    tmp = strlen(menu_options->title) ;
  219.    stream[-1] = tmp ;
  220.    stream[-3] = (width-tmp)/2 ;
  221.    memcpy( stream, menu_options->title, tmp ) ;
  222.    stream += tmp ;
  223.    *((int *)stream)++ = 0x01E2 ;  /* set color back to normal */
  224.    *((int *)stream)++ = 0x02A0 ;  /* skip next line */
  225.    for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
  226.       if (menu_item->type != M_IGNORE)
  227.          {
  228.          *((int *)stream)++ = 0x01B0 ;  /* move to start of next line */
  229.          switch (menu_item->type)
  230.             {
  231.             case M_ITEM:
  232.                *((int *)stream)++ = 0x02A1 ;  /* leave a blank at start of line */
  233.                *stream++ = 0x98 ;
  234.                *stream++ = tmp = strlen(menu_item->entry) ;
  235.                memcpy((char *)stream,menu_item->entry,tmp) ;
  236.                stream += tmp ;
  237.                *stream++ = 0xB1 ;
  238.                *stream++ = width - tmp - (two_keys ? 6 : 5 ) ;
  239.                if (two_keys)
  240.                   {
  241.                   *stream++ = (menu_item->key2) ? 0x62 : 0x61 ;
  242.                   *stream++ = (menu_item->key1) ? menu_item->key1 : ' ' ;
  243.                   if (menu_item->key2)
  244.                      *stream++ = menu_item->key2 ;
  245.                   }
  246.                else
  247.                   {
  248.                   *stream++ = 0x61 ;
  249.                   *stream++ = (menu_item->key1) ? menu_item->key1 : ' ' ;
  250.                   }
  251.                break ;
  252.             case M_TEXT:
  253.             case M_HTEXT:
  254.                *((int *)stream)++ = 0x02A1 ;  /* leave a blank at start of line */
  255.                if (menu_item->entry && (tmp = strlen(menu_item->entry)) > 0)
  256.                   {
  257.                   if (menu_item->type == M_HTEXT)
  258.                      *((int *)stream)++ = 0x02E2 ; /* change to highlighted */
  259.                   *stream++ = 0x98 ;
  260.                   *stream++ = tmp ;
  261.                   memcpy(stream,menu_item->entry,tmp) ;
  262.                   stream += tmp ;
  263.                   if (menu_item->type == M_HTEXT)
  264.                      *((int *)stream)++ = 0x01E2 ; /* change back to normal */
  265.                   }
  266.                break ;
  267.             case M_CENTER:
  268.             case M_HCENTER:
  269.                if (menu_item->entry && *menu_item->entry)
  270.                   {
  271.                   if (menu_item->type == M_HCENTER)
  272.                      *((int *)stream)++ = 0x02E2 ; /* change to highlighted */
  273.                   tmp = strlen(menu_item->entry) ;
  274.                   *stream++ = 0xA1 ;
  275.                   *stream++ = (width - tmp) / 2 ;
  276.                   *stream++ = 0x98 ;
  277.                   *stream++ = tmp ;
  278.                   memcpy(stream,menu_item->entry,tmp) ;
  279.                   stream += tmp ;
  280.                   if (menu_item->type == M_HCENTER)
  281.                      *((int *)stream)++ = 0x01E2 ; /* change back to normal */
  282.                   }
  283.                break ;
  284.             case M_SEP:
  285.                *((int *)stream)++ = 0x01A1 ;  /* don't leave a blank at start of line */
  286.                *stream++ = 0x88 ;             /* replicate key across line */
  287.                *stream++ = width-2 ;
  288.                *stream++ = menu_item->key1 ;
  289.                break ;
  290.             case M_SPECIAL:
  291.                {
  292.                char *keyname = strrchr( menu_item->entry, ' ' ) + 1 ;
  293.  
  294.                *((int *)stream)++ = 0x02A1 ;  /* leave a blank at start of line */
  295.                *stream++ = 0x98 ;
  296.                *stream++ = tmp = keyname - menu_item->entry ;
  297.                memcpy( stream, menu_item->entry, tmp ) ;
  298.                stream += tmp ;
  299.                *stream++ = 0xB1 ;   /* skip over to end of line */
  300.                *stream++ = width - 4 - tmp - strlen(keyname) ;
  301.                *stream++ = 0x98 ;   /* show key to press */
  302.                *stream++ = tmp = strlen(keyname) ;
  303.                memcpy( stream, keyname, tmp ) ;
  304.                stream += tmp ;
  305.                }
  306.                break ;
  307.             }
  308.          }
  309.    *((int *)stream)++ = 0x18E5 ;
  310.    *stream++ = 0xFF ;
  311.    if (two_keys)
  312.       *stream++ = ((int *)stream_start)[1] + 1 ;
  313.    else
  314.       *stream++ = ((int *)stream_start)[1] ;
  315.    tmp = F_READARRAY ;
  316.    if (menu_options->allow_kbd)
  317.       tmp |= F_ALLOWKBD ;
  318.    if (menu_options->left_button)
  319.       tmp |= F_LEFTBUTTON ;
  320.    if (menu_options->right_button)
  321.       tmp |= F_RIGHTBUTTON ;
  322.    *stream++ = tmp ;
  323.    *((int *)stream)++ = 0 ;
  324.    *((int *)stream)++ = 0x0209 ;
  325.    menu_item = menu_items ;
  326.    line = 3 ;
  327.    while (menu_item->type != M_END)
  328.       {
  329.       if (menu_item->type == M_ITEM || menu_item->type == M_SPECIAL)
  330.          {
  331.          *stream++ = line ;
  332.          *stream++ = 1 ;
  333.          *stream++ = line ;
  334.          *stream++ = width-2 ;
  335.          *stream++ = (menu_item->selected) ? 0xC0 : 0xC0 | F_SELECTED ;
  336.          *stream++ = menu_item->key1 ;
  337.          *stream++ = 1 ;
  338.          *stream++ = two_keys ? menu_item->key2 : 0 ;
  339.          }
  340.       if (menu_item->type != M_IGNORE)
  341.          line++ ;
  342.       menu_item++ ;
  343.       }
  344.    if (two_keys)
  345.       {
  346.       *stream++ = 2 ;
  347.       *stream++ = (width+1)/2-1 ;
  348.       *stream++ = 2 ;
  349.       *stream++ = (width+1)/2-1 ;
  350.       *stream++ = 0x40 ;
  351.       *stream++ = 0 ;
  352.       *stream++ = 0 ;
  353.       *stream++ = 0 ;
  354.       }
  355.    memcpy( stream, fixed_stream_trailer, sizeof( fixed_stream_trailer )) ;
  356.    if (menu_options->marker)
  357.       stream[sizeof(fixed_stream_trailer)-1] = menu_options->marker ;
  358.    return (void *) stream_start ;
  359. }
  360.  
  361. /* End of UIMBUILD.C */
  362.